package com.github.m6d21.sso.business.configuration;

import com.github.m6d21.sso.common.util.MapUtil;
import com.github.m6d21.sso.support.model.Response;
import com.github.m6d21.sso.support.util.ResponseUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
@Api(value = "global-error", description = "错误处理")
@RequestMapping("${server.error.path:${error.path:/error}}")
public class GlobalErrorController extends AbstractErrorController {

    private static final Logger LOG = LoggerFactory.getLogger(
        GlobalErrorController.class);


    private final ErrorProperties errorProperties;

    public GlobalErrorController(ErrorAttributes errorAttributes,
        ServerProperties serverProperties, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, errorViewResolvers);
        Assert.notNull(serverProperties, "serverProperties must not be null");
        this.errorProperties = serverProperties.getError();
    }

    @Override
    public String getErrorPath() {
        return this.errorProperties.getPath();
    }

    @ApiOperation(value = "页面错误处理")
    @RequestMapping(produces = {"text/html"})
    public ModelAndView errorHtml(HttpServletRequest request,
        HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
            request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        String path = "path";
        LOG.warn("{请求[{}]出错，错误码：{}", MapUtil.valueOf(path, model), status.value());
        return (modelAndView == null ? new ModelAndView("/error.html", model) : modelAndView);
    }


    @ApiOperation(value = "非页面错误处理")
    @RequestMapping
    @ResponseBody
    public Response<Object> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request,
            isIncludeStackTrace(request, MediaType.ALL));
        String path = "path";
        HttpStatus status = getStatus(request);
        LOG.warn("{请求[{}]出错，错误码：{}", MapUtil.valueOf(path, body), status.value());
        return ResponseUtil.fail(status.value(), status.getReasonPhrase(), MapUtil.valueOf(path, body));
    }

    private boolean isIncludeStackTrace(HttpServletRequest request,
        MediaType produces) {
        IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
        if (include == IncludeStacktrace.ALWAYS) {
            return true;
        }
        if (include == IncludeStacktrace.ON_TRACE_PARAM) {
            return getTraceParameter(request);
        }
        return false;
    }

    private ErrorProperties getErrorProperties() {
        return this.errorProperties;
    }

}
